package student.aistar.design.singleton.version04;

import java.io.Serializable;

/**
 * 枚举单例实现方式
 */
public class Singleton04 implements Serializable {

    private Singleton04(){
        System.out.println("私有化构造");
    }

    //内部的枚举类型
    public enum SingletonEnum{
        //枚举常量的实例
        INSTANCE;//public static final SingletonEnum INSTANCE = new SingletonEnum();

        //final修饰的变量要赋值
        private Singleton04 singleton04;

        //枚举类型提供一个空参构造 - 枚举类型是不能new的
        SingletonEnum() {
            this.singleton04 = new Singleton04();
        }

        //提供一个普通方法
        public Singleton04 getInstance(){
            return singleton04;
        }
    }

    //外部类肯定要提供一个方法, 返回自己的一个唯一实例的
    public static Singleton04 getInstance(){
        //利用一个枚举的单例的特性
        return SingletonEnum.INSTANCE.getInstance();
    }

    public static void main(String[] args) {
        //①Singleton04.getInstance();
        //②return SingletonEnum.INSTANCE.getInstance();
        // JVM 就开始唤醒类加载器ClassLoader - loadClass方法[synchronized] - 加载枚举类型SingletonEnum
        // 类加载的过程本身就是一个线程安全的过程, 只会有一个去将枚举类型加载到JVM内存

        //③INSTANCE;
        //  枚举类型一旦被加载, 那么它里面的枚举常量立即就会被初始化分配空间, 因为枚举常量都是用static
        //  修饰的, 所以机会只有一次, 枚举常量在内存中也只会存在一份而已

        //④SingletonEnum.INSTANCE - 多个线程拿到的肯定是同一个INSTANCE

        //⑤SingletonEnum(){ intance = new Singleton04();}
        //因为枚举常量赋值只会赋值一次, 所以构造方法只会执行一次
        //instance = new Singleton04(); //只会执行一次
        Singleton04 s = Singleton04.getInstance();
        Singleton04 s1 = Singleton04.getInstance();
        Singleton04 s2 = SingletonEnum.INSTANCE.getInstance();

        //⑥SingletonEnum.INSTANCE.getInstance(); //获取intance
        System.out.println(s == s2);

    }
}
